/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com */

/*
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef TRI_ABSTRACT_ENTITY_H_
#define TRI_ABSTRACT_ENTITY_H_

#include <string>
#include <map>

#include "base/node.h" 
#include "base/animate.h"
#include "base/matrix.h"
#include "base/vector.h"

#include "texture.h"
#include "material.h"
#include "camera.h"
#include "events.h"


namespace tri
{

enum{
	IGNORE_RENDER_PRIORITY,
	BACKGROUND_PRIORITY,
	SCENERY_PRIORITY,
	NORMAL_PRIORITY,
	SPECAIL_EFFECTS_PRIORITY,
	OVERLAY_PRIORITY,
};

class abstract_entity:public node::Node,public tri::events::event_entity
{
public:
	abstract_entity();
	virtual ~abstract_entity();
	
	/**
	 * Component specific rendering. Subclasses must overide this method.
	 * routines. Do not call this methods directly
	 * use render().
	 */
	virtual void display()=0;
	virtual void secondaryDisplay();
	void setVisualRotation(tri::vector v,float t=0);
	
	
	/**
	 * Render the object to the screen.
	 */
	virtual void render();
	
	/**
	 * Get the unique id assosiated with this
	 * entity.
	 */
	unsigned int getEntityID();
	
	
	anivector* getPositionVector();
	anivector* getRotationVector();
	
	/**
	 * Set object position
	 */
	void setPosition(float x,float y,float z);
	void setPosition(tri::vector v);
	
	/**
	 * Set object rotation
	 */
	void setRotation(float x,float y,float z);
	void setRotation(tri::vector v);
	
	/**
	 * Set object position
	 */
	void setTargetPosition(float x,float y,float z,float t=1.0);
	void setTargetPosition(tri::vector v,float t=1.0);
	/**
	 * Set object rotation
	 */
	void setTargetRotation(float x,float y,float z,float t=1.0);
	void setTargetRotation(tri::vector v,float t=1.0);
	
	/**
	 * Get the entity's position
	 */
	void getPosition(float *v);
	tri::vector getPosition();
	
	/**
	 * Get the entity's rotation
	 */
	void getRotation(float *v);
	tri::vector getRotation();
	
	void setScale(tri::vector v);
	void setScale(float x, float y, float z);
	tri::vector getScale();
	
	/*
	 * Set object to be rendered in wireframe
	 */
	void setWireFrame(bool b);
	
	/*
	 * Set Load Name
	 */
	void setLoadName(bool b);
	
	/**	
	 * Set object size
	 */
	void setSize(float x,float y,float z);
	void setTargetSize(float x,float y,float z,float t=1.0);
	void setSize(float *v);
	void setSize(tri::vector v);
	void getSize(float *v);
	tri::vector getSize();
	void get_model_matrix(tri::matrix* m);
	tri::vector getAbsolutePosition();
	/**
	 * Does this entity want to be repainted. This will
	 * be because it appearence has changed or its position/rotaion 
	 * has changed.
	 */
	bool repaintRequested();
	
	virtual void addEntity(abstract_entity* e);
	abstract_entity* getByEntityID(unsigned int id);
	bool loadName();
	void enableRecursiveRender(bool b);
	void setVisible(bool);
	bool isVisible();
	
	virtual void update();
	virtual void setName(std::string name);
	virtual std::string getName();
	void updateModelViewMatrix();
	
	tri::vector getPrevPosition();
	void savePosition(tri::vector);
	
	static camera* getActiveCamera();
	static void setActiveCamera(camera*);
	
	
	//material and texture methods
	
	void setColor(int r, int g, int b, int a=255);
	void getColor(int& r, int& g, int& b, int& a);
	void setTargetColor(int r, int g, int b, int a=255, float t = 1.0);
	void applyColor();
	void setColor(graphics::RGBA);
	void setTargetColor(graphics::RGBA,float t = 1.0);
	tri::graphics::color getColor();
	tri::graphics::RGBA getColorAsRGBA();
	
	void setImage(std::string image,bool filter=false,bool mipmap=false);
	std::string getImage();
	bool isImageFiltered();
	bool isImageMipmap();
	tri::texture* getTexture();
	
	void setMaterial(std::string);
	std::string getMaterial();
	Material* getMaterialPointer();
	
	
	
protected:	
	//private methods for rendering node entities.
	void render_children();
	void render_next();
	void update_children();
	void update_next();
	void applyTranformation();
	bool repaintQuestedByChildren();
	bool repaintQuestedByNext();
	/**
	 *Request that this entity be repainted
	 */ 
	void requestRepaint();
	
	
		
	
private:
	//transformation variables
	tri::anivector pos;
	tri::anivector rot;
	tri::anivector size;
	tri::anivector scale;
	tri::anivector mVisualRotation;
	std::string name;
	tri::vector mPrevPos;
	
	//object information
	static unsigned int entity_count;
	unsigned int entity_id;
	bool load_name;
	bool renderchildren;
	tri::matrix model_view_matrix;
	bool mWireFrameMode;
	bool mRepaintRequest;
	bool mVisible;
	static camera* mActiveCamera;
	
	int mRenderPriority;
	bool enableRenderPriority;
	
	Material mMaterial;
	std::string mMaterialPointer;
	
	static int mCurrentRenderPriority;
};

}

#endif /*TRI_ENTITY_H_*/
